home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / utilities / isfast / libisfast / visinfo.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  28KB  |  1,166 lines

  1. /*
  2.  * Copyright (c) 1994 Silicon Graphics, Inc.
  3.  * 
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee,
  6.  * provided that (i) the above copyright notices and this permission
  7.  * notice appear in all copies of the software and related documentation,
  8.  * and (ii) the name of Silicon Graphics may not be used in any
  9.  * advertising or publicity relating to the software without the specific,
  10.  * prior written permission of Silicon Graphics.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  15.  * 
  16.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
  17.  * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
  18.  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  19.  * OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
  20.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  21.  * OF THIS SOFTWARE.
  22.  */
  23.  
  24.  
  25. /*****************************************************************************
  26.  * visPixelFormat, visGetGLXVisualInfo - tools for choosing OpenGL pixel
  27.  *    formats
  28.  *****************************************************************************/
  29.  
  30.  
  31. #include <ctype.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include "visinfo.h"
  36.  
  37. #define DEBUG 0
  38.  
  39. #define Emit(x)        *ConditionP++ = (x)
  40. #define EmitKey(x)    *SortKeyP++ = (x)
  41.  
  42.  
  43.  
  44. /*
  45.  * Tokens that are used by the parser and expression evaluator:
  46.  */
  47.  
  48. #define VIS_OP_END        0    /* end of expression        */
  49. #define VIS_OP_ADD        1    /* C integer +            */
  50. #define VIS_OP_AND        2    /* C integer &&            */
  51. #define VIS_OP_DIV        3    /* C integer /            */
  52. #define VIS_OP_EQ        4    /* C integer ==            */
  53. #define VIS_OP_GE        5    /* C integer >=            */
  54. #define VIS_OP_GT        6    /* C integer >            */
  55. #define VIS_OP_LE        7    /* C integer <=            */
  56. #define VIS_OP_LT        8    /* C integer <            */
  57. #define VIS_OP_MOD        9    /* C integer %            */
  58. #define VIS_OP_MUL        10    /* C integer *            */
  59. #define VIS_OP_NE        11    /* C integer !=            */
  60. #define VIS_OP_NEGATE        12    /* C integer unary -        */
  61. #define VIS_OP_NOT        13    /* C integer unary !        */
  62. #define VIS_OP_OR        14    /* C integer ||            */
  63. #define VIS_OP_SUB        15    /* C integer -            */
  64.  
  65. #define VIS_TOK_CONSTANT    16    /* integer constants        */
  66. #define VIS_TOK_ERROR        17    /* erroneous token        */
  67. #define VIS_TOK_LPAREN        18    /* (                */
  68. #define VIS_TOK_RPAREN        19    /* )                */
  69. #define VIS_TOK_SEPARATOR    20    /* ,                */
  70.  
  71. #define VIS_SORT_MAX        21    /* sort largest value first    */
  72. #define VIS_SORT_MIN        22    /* sort smallest value first    */
  73.  
  74. #define VIS_FIRST_VAR        23
  75. #define VIS_VAR_A        23    /* alpha channel size        */
  76. #define VIS_VAR_ACCUM_A        24    /* accum alpha channel size    */
  77. #define VIS_VAR_ACCUM_B        25    /* accum blue channel size    */
  78. #define VIS_VAR_ACCUM_G        26    /* accum green channel size    */
  79. #define VIS_VAR_ACCUM_R        27    /* accum red channel size    */
  80. #define VIS_VAR_ACCUM_RGB    28    /* min(accum r, g, b)        */
  81. #define VIS_VAR_ACCUM_RGBA    29    /* min(accum r, g, b, a)    */
  82. #define VIS_VAR_AUX        30    /* number of aux color buffers    */
  83. #define VIS_VAR_B        31    /* blue channel size        */
  84. #define VIS_VAR_CI        32    /* color index buffer size    */
  85. #define VIS_VAR_DB        33    /* nonzero if double-buffered    */
  86. #define VIS_VAR_G        34    /* green channel size        */
  87. #define VIS_VAR_GLX        35    /* nonzero if supports OpenGL    */
  88. #define VIS_VAR_ID        36    /* visual (or pixel format) id    */
  89. #define VIS_VAR_LEVEL        37    /* buffer level            */
  90. #define VIS_VAR_MAIN        38    /* nonzero for main buffers    */
  91. #define VIS_VAR_MONO        39    /* nonzero if monoscopic    */
  92. #define VIS_VAR_MS        40    /* number of (multi)samples    */
  93. #define VIS_VAR_OVERLAY        41    /* nonzero for overlay buffers    */
  94. #define VIS_VAR_R        42    /* red channel size        */
  95. #define VIS_VAR_RGB        43    /* min(r, g, b)            */
  96. #define VIS_VAR_RGBA        44    /* min(r, g, b, a)        */
  97. #define VIS_VAR_S        45    /* stencil buffer size        */
  98. #define VIS_VAR_SB        46    /* nonzero if single-buffered    */
  99. #define VIS_VAR_STEREO        47    /* nonzero if stereoscopic    */
  100. #define VIS_VAR_UNDERLAY    48    /* nonzero for underlay buffers    */
  101. #define VIS_VAR_Z        49    /* depth (z) buffer size    */
  102. #define VIS_LAST_VAR        49
  103.  
  104.  
  105. /*
  106.  * Structures for parsing, sorting, and evaluating conditions:
  107.  */
  108.  
  109. #define VIS_KEYSIZE        ((VIS_LAST_VAR-VIS_FIRST_VAR+1)*2+1)
  110. static int SortKeys[VIS_KEYSIZE];
  111. static int* SortKeyP;
  112.  
  113. #define VIS_CONDSIZE        100
  114. static int Condition[VIS_CONDSIZE];
  115. static int* ConditionP;
  116.  
  117. #define VIS_VARSIZE        128
  118. static char* CriteriaP;
  119. static int Symbol;
  120. static int Value;
  121.  
  122. #define VIS_STACKSIZE        100
  123.  
  124.  
  125. /*
  126.  * Parser status values:
  127.  */
  128.  
  129. #define VIS_PRESENT        0
  130. #define VIS_ABSENT        1
  131. #define VIS_SYNTAX_ERROR    2
  132.  
  133.  
  134. /*
  135.  * Name-to-value mapping for converting variables to token values:
  136.  */
  137.  
  138. typedef struct {
  139.     char* name;
  140.     int value;
  141.     } NameMappingT;
  142.  
  143.  
  144. /*
  145.  * Pointer to X11 display (made global for use by qsort auxiliary routines):
  146.  */
  147.  
  148. static Display* DisplayPointer;
  149.  
  150.  
  151.  
  152. static int AcceptableVisual(XVisualInfo* v);
  153. static int CompareNames(const void* n1, const void* n2);
  154. static int CompareVisuals(const void* left, const void* right);
  155. static int FetchVariable(XVisualInfo* visual, int variable);
  156. static void FilterVisuals(XVisualInfo** vp, int* n);
  157. static void GetSymbol(void);
  158. static int LookupName(char* name);
  159. static int ParseArithExpr(void);
  160. static int ParseArithFactor(void);
  161. static int ParseArithPrimary(void);
  162. static int ParseArithTerm(void);
  163. static int ParseBoolFactor(void);
  164. static int ParseBoolTerm(void);
  165. static int ParseCriteria(void);
  166. static int ParseCriterion(void);
  167. static int ParseExpression(void);
  168. static int ParseSortKey(void);
  169.  
  170.  
  171.  
  172. #if DEBUG
  173. static char* SymbolToString(int symbol);
  174. #endif
  175.  
  176.  
  177.  
  178. /******************************************************************************
  179.  * AcceptableVisual
  180.  *    Evaluate selection expression for a single XVisualInfo structure.
  181.  *    Return nonzero if the visual meets all conditions.
  182.  *****************************************************************************/
  183.  
  184. static int
  185. AcceptableVisual(XVisualInfo* v) {
  186.     int stack[VIS_STACKSIZE];
  187.     int* sp;
  188.     int* cp;
  189.  
  190.     /*
  191.      * Initialize evaluation stack.  Set pointer into the stack,
  192.      * rather than at the very beginning, to allow fetching operands
  193.      * without checking stack depth.
  194.      */
  195.     sp = stack + 1;
  196.  
  197.     /*
  198.      * Process the RPN expression string:
  199.      */
  200.     for (cp = Condition; *cp != VIS_OP_END; ) {
  201.         int right = *--sp;
  202.         int left = sp[-1];
  203.         int result;
  204.  
  205.         switch (*cp++) {
  206.             case VIS_OP_ADD:
  207.                 result = left + right;
  208.                 break;
  209.             case VIS_OP_AND:
  210.                 result = left && right;
  211.                 break;
  212.             case VIS_OP_DIV:
  213.                 if (right == 0)
  214.                     return 0;
  215.                 result = left / right;
  216.                 break;
  217.             case VIS_OP_EQ:
  218.                 result = left == right;
  219.                 break;
  220.             case VIS_OP_GE:
  221.                 result = left >= right;
  222.                 break;
  223.             case VIS_OP_GT:
  224.                 result = left > right;
  225.                 break;
  226.             case VIS_OP_LE:
  227.                 result = left <= right;
  228.                 break;
  229.             case VIS_OP_LT:
  230.                 result = left < right;
  231.                 break;
  232.             case VIS_OP_MOD:
  233.                 if (right == 0)
  234.                     return 0;
  235.                 result = left % right;
  236.                 break;
  237.             case VIS_OP_MUL:
  238.                 result = left * right;
  239.                 break;
  240.             case VIS_OP_NE:
  241.                 result = left != right;
  242.                 break;
  243.             case VIS_OP_NEGATE:
  244.                 ++sp;    /* put back unused operand */
  245.                 result = - right;
  246.                 break;
  247.             case VIS_OP_NOT:
  248.                 ++sp;    /* put back unused operand */
  249.                 result = ! right;
  250.                 break;
  251.             case VIS_OP_OR:
  252.                 result = left || right;
  253.                 break;
  254.             case VIS_OP_SUB:
  255.                 result = left - right;
  256.                 break;
  257.             case VIS_TOK_CONSTANT:
  258.                 sp += 2;/* put back unused operands */
  259.                 result = *cp++;
  260.                 break;
  261.             default:    /* must be a variable */
  262.                 sp += 2;/* put back unused operands */
  263.                 result = FetchVariable(v, cp[-1]);
  264.                 break;
  265.             }
  266.         
  267.         sp[-1] = result;
  268.         }
  269.  
  270.     return stack[1];
  271.     }
  272.  
  273.  
  274.  
  275. /******************************************************************************
  276.  * CompareNames
  277.  *    Name comparison function used by bsearch() in LookupName().
  278.  *****************************************************************************/
  279.  
  280. static int
  281. CompareNames(const void* n1, const void* n2) {
  282.     return strcmp(((NameMappingT*) n1)->name, ((NameMappingT*) n2)->name);
  283.     }
  284.  
  285.  
  286.  
  287. /******************************************************************************
  288.  * CompareVisuals
  289.  *    Visual comparison function used by qsort() in visGetGLXVisualInfo().
  290.  *****************************************************************************/
  291.  
  292. static int
  293. CompareVisuals(const void* left, const void* right) {
  294.     int varLeft, varRight;
  295.     int difference;
  296.     int k;
  297.  
  298.     for (k = 0; SortKeys[k] != VIS_OP_END; k += 2) {
  299.         varLeft = FetchVariable(*(XVisualInfo**) left, SortKeys[k + 1]);
  300.         varRight= FetchVariable(*(XVisualInfo**) right,SortKeys[k + 1]);
  301.         difference = varLeft - varRight;
  302.         if (SortKeys[k] == VIS_SORT_MAX)   /* sort largest first? */
  303.             difference = -difference;
  304.         if (difference)
  305.             return difference;
  306.         }
  307.  
  308.     return 0;
  309.     }
  310.  
  311.  
  312.  
  313. /******************************************************************************
  314.  * FetchVariable
  315.  *    Fetch the value of a variable from an XVisualInfo structure
  316.  *****************************************************************************/
  317.  
  318. static int
  319. FetchVariable(XVisualInfo* visual, int variable) {
  320.     int var;
  321.     int i;
  322.  
  323.     switch (variable) {
  324.         case VIS_VAR_A:
  325.             glXGetConfig(DisplayPointer, visual, GLX_RGBA, &var);
  326.             if (!var)
  327.                 break;
  328.             glXGetConfig(DisplayPointer, visual, GLX_ALPHA_SIZE,
  329.                 &var);
  330.             break;
  331.         case VIS_VAR_ACCUM_A:
  332.             glXGetConfig(DisplayPointer, visual,
  333.                 GLX_ACCUM_ALPHA_SIZE, &var);
  334.             break;
  335.         case VIS_VAR_ACCUM_B:
  336.             glXGetConfig(DisplayPointer, visual,
  337.                 GLX_ACCUM_BLUE_SIZE, &var);
  338.             break;
  339.         case VIS_VAR_ACCUM_G:
  340.             glXGetConfig(DisplayPointer, visual,
  341.                 GLX_ACCUM_GREEN_SIZE, &var);
  342.             break;
  343.         case VIS_VAR_ACCUM_R:
  344.             glXGetConfig(DisplayPointer, visual, GLX_ACCUM_RED_SIZE,
  345.                 &var);
  346.             break;
  347.         case VIS_VAR_ACCUM_RGB:
  348.             glXGetConfig(DisplayPointer, visual, GLX_ACCUM_RED_SIZE,
  349.                 &var);
  350.             glXGetConfig(DisplayPointer, visual,
  351.                 GLX_ACCUM_GREEN_SIZE, &i);
  352.             if (i < var)
  353.                 var = i;
  354.             glXGetConfig(DisplayPointer, visual,
  355.                 GLX_ACCUM_BLUE_SIZE, &i);
  356.             if (i < var)
  357.                 var = i;
  358.             break;
  359.         case VIS_VAR_ACCUM_RGBA:
  360.             glXGetConfig(DisplayPointer, visual, GLX_ACCUM_RED_SIZE,
  361.                 &var);
  362.             glXGetConfig(DisplayPointer, visual,
  363.                 GLX_ACCUM_GREEN_SIZE, &i);
  364.             if (i < var)
  365.                 var = i;
  366.             glXGetConfig(DisplayPointer, visual,
  367.                 GLX_ACCUM_BLUE_SIZE, &i);
  368.             if (i < var)
  369.                 var = i;
  370.             glXGetConfig(DisplayPointer, visual,
  371.                 GLX_ACCUM_ALPHA_SIZE, &i);
  372.             if (i < var)
  373.                 var = i;
  374.             break;
  375.         case VIS_VAR_AUX:
  376.             glXGetConfig(DisplayPointer, visual, GLX_AUX_BUFFERS,
  377.                 &var);
  378.             break;
  379.         case VIS_VAR_B:
  380.             glXGetConfig(DisplayPointer, visual, GLX_RGBA, &var);
  381.             if (!var)
  382.                 break;
  383.             glXGetConfig(DisplayPointer, visual, GLX_BLUE_SIZE,
  384.                 &var);
  385.             break;
  386.         case VIS_VAR_CI:
  387.             glXGetConfig(DisplayPointer, visual, GLX_RGBA, &var);
  388.             if (var) {
  389.                 var = 0;
  390.                 break;
  391.                 }
  392.             glXGetConfig(DisplayPointer, visual, GLX_BUFFER_SIZE,
  393.                 &var);
  394.             break;
  395.         case VIS_VAR_DB:
  396.             glXGetConfig(DisplayPointer, visual, GLX_DOUBLEBUFFER,
  397.                 &var);
  398.             break;
  399.         case VIS_VAR_G:
  400.             glXGetConfig(DisplayPointer, visual, GLX_RGBA, &var);
  401.             if (!var)
  402.                 break;
  403.             glXGetConfig(DisplayPointer, visual, GLX_GREEN_SIZE,
  404.                 &var);
  405.             break;
  406.         case VIS_VAR_GLX:
  407.             glXGetConfig(DisplayPointer, visual, GLX_USE_GL,
  408.                 &var);
  409.             break;
  410.         case VIS_VAR_ID:
  411.             var = visual->visualid;
  412.             break;
  413.         case VIS_VAR_LEVEL:
  414.             glXGetConfig(DisplayPointer, visual, GLX_LEVEL,
  415.                 &var);
  416.             break;
  417.         case VIS_VAR_MAIN:
  418.             glXGetConfig(DisplayPointer, visual, GLX_LEVEL,
  419.                 &var);
  420.             var = var == 0;
  421.             break;
  422.         case VIS_VAR_MONO:
  423.             glXGetConfig(DisplayPointer, visual, GLX_STEREO,
  424.                 &var);
  425.             var = !var;
  426.             break;
  427.         case VIS_VAR_MS:
  428. #ifdef GL_SGIS_multisample
  429.             glXGetConfig(DisplayPointer, visual, GLX_SAMPLES_SGIS,
  430.                 &var);
  431. #else
  432.             var = 0;
  433. #endif
  434.             break;
  435.         case VIS_VAR_OVERLAY:
  436.             glXGetConfig(DisplayPointer, visual, GLX_LEVEL,
  437.                 &var);
  438.             var = var > 0;
  439.             break;
  440.         case VIS_VAR_R:
  441.             glXGetConfig(DisplayPointer, visual, GLX_RGBA, &var);
  442.             if (!var)
  443.                 break;
  444.             glXGetConfig(DisplayPointer, visual, GLX_RED_SIZE,
  445.                 &var);
  446.             break;
  447.         case VIS_VAR_RGB:
  448.             glXGetConfig(DisplayPointer, visual, GLX_RGBA, &var);
  449.             if (!var)
  450.                 break;
  451.             glXGetConfig(DisplayPointer, visual, GLX_RED_SIZE,
  452.                 &var);
  453.             glXGetConfig(DisplayPointer, visual, GLX_GREEN_SIZE,
  454.                 &i);
  455.             if (i < var)
  456.                 var = i;
  457.             glXGetConfig(DisplayPointer, visual, GLX_BLUE_SIZE,
  458.                 &i);
  459.             if (i < var)
  460.                 var = i;
  461.             break;
  462.         case VIS_VAR_RGBA:
  463.             glXGetConfig(DisplayPointer, visual, GLX_RGBA, &var);
  464.             if (!var)
  465.                 break;
  466.             glXGetConfig(DisplayPointer, visual, GLX_RED_SIZE,
  467.                 &var);
  468.             glXGetConfig(DisplayPointer, visual, GLX_GREEN_SIZE,
  469.                 &i);
  470.             if (i < var)
  471.                 var = i;
  472.             glXGetConfig(DisplayPointer, visual, GLX_BLUE_SIZE,
  473.                 &i);
  474.             if (i < var)
  475.                 var = i;
  476.             glXGetConfig(DisplayPointer, visual, GLX_ALPHA_SIZE,
  477.                 &i);
  478.             if (i < var)
  479.                 var = i;
  480.             break;
  481.         case VIS_VAR_S:
  482.             glXGetConfig(DisplayPointer, visual, GLX_STENCIL_SIZE,
  483.                 &var);
  484.             break;
  485.         case VIS_VAR_SB:
  486.             glXGetConfig(DisplayPointer, visual, GLX_DOUBLEBUFFER,
  487.                 &var);
  488.             var = !var;
  489.             break;
  490.         case VIS_VAR_STEREO:
  491.             glXGetConfig(DisplayPointer, visual, GLX_STEREO,
  492.                 &var);
  493.             break;
  494.         case VIS_VAR_UNDERLAY:
  495.             glXGetConfig(DisplayPointer, visual, GLX_LEVEL,
  496.                 &var);
  497.             var = var < 0;
  498.             break;
  499.         case VIS_VAR_Z:
  500.             glXGetConfig(DisplayPointer, visual, GLX_DEPTH_SIZE,
  501.                 &var);
  502.             break;
  503.         }
  504.  
  505.     return var;
  506.     }
  507.  
  508.  
  509.  
  510. /******************************************************************************
  511.  * FilterVisuals
  512.  *    Remove unwanted visuals from consideration
  513.  *****************************************************************************/
  514.  
  515. static void
  516. FilterVisuals(XVisualInfo** vp, int* n) {
  517.     int i;
  518.     int j;
  519.  
  520.     /*
  521.      * Evaluate the conditional expression for each visual and
  522.      * eliminate pointers to visuals for which the expression is zero:
  523.      */
  524.     j = 0;
  525.     for (i = 0; i < *n; ++i) {
  526.         if (AcceptableVisual(vp[i]))
  527.             vp[j++] = vp[i];
  528.         }
  529.     *n = j;
  530.     }
  531.  
  532.  
  533.  
  534. /******************************************************************************
  535.  * GetSymbol
  536.  *    Fetch next symbol from the input string
  537.  *****************************************************************************/
  538.  
  539. static void
  540. GetSymbol(void) {
  541.     char var[VIS_VARSIZE];
  542.     char* varP;
  543.     char* p;
  544.     char c;
  545.     char nextC;
  546.  
  547.     p = CriteriaP;
  548.     while (isspace(*p))
  549.         ++p;
  550.  
  551.     if (isalpha(*p)) {
  552.         varP = var;
  553.         while (isalnum(*p))
  554.             *varP++ = tolower(*p++);
  555.         *varP = '\0';
  556.         CriteriaP = p;
  557.         Symbol = LookupName(var);
  558.         return;
  559.         }
  560.  
  561.     if (isdigit(*p)) {
  562.         Value = strtol(p, &CriteriaP, 0);
  563.         Symbol = VIS_TOK_CONSTANT;
  564.         return;
  565.         }
  566.  
  567.     Symbol = VIS_TOK_ERROR;
  568.     c = *p++;
  569.     if (c)
  570.         nextC = *p;
  571.     switch (c) {
  572.         case '|':
  573.             if (nextC == '|') {
  574.                 ++p;
  575.                 Symbol = VIS_OP_OR;
  576.                 }
  577.             break;
  578.         case '&':
  579.             if (nextC == '&') {
  580.                 ++p;
  581.                 Symbol = VIS_OP_AND;
  582.                 }
  583.             break;
  584.         case '<':
  585.             if (nextC == '=') {
  586.                 ++p;
  587.                 Symbol = VIS_OP_LE;
  588.                 }
  589.             else
  590.                 Symbol = VIS_OP_LT;
  591.             break;
  592.         case '>':
  593.             if (nextC == '=') {
  594.                 ++p;
  595.                 Symbol = VIS_OP_GE;
  596.                 }
  597.             else
  598.                 Symbol = VIS_OP_GT;
  599.             break;
  600.         case '=':
  601.             if (nextC == '=') {
  602.                 ++p;
  603.                 Symbol = VIS_OP_EQ;
  604.                 }
  605.             break;
  606.         case '!':
  607.             if (nextC == '=') {
  608.                 ++p;
  609.                 Symbol = VIS_OP_NE;
  610.                 }
  611.             else
  612.                 Symbol = VIS_OP_NOT;
  613.             break;
  614.         case '+':
  615.             Symbol = VIS_OP_ADD;
  616.             break;
  617.         case '-':
  618.             Symbol = VIS_OP_SUB;
  619.             break;
  620.         case '*':
  621.             Symbol = VIS_OP_MUL;
  622.             break;
  623.         case '/':
  624.             Symbol = VIS_OP_DIV;
  625.             break;
  626.         case '%':
  627.             Symbol = VIS_OP_MOD;
  628.             break;
  629.         case ',':
  630.             Symbol = VIS_TOK_SEPARATOR;
  631.             break;
  632.         case '(':
  633.             Symbol = VIS_TOK_LPAREN;
  634.             break;
  635.         case ')':
  636.             Symbol = VIS_TOK_RPAREN;
  637.             break;
  638.         case '\0':
  639.             Symbol = VIS_OP_END;
  640.             --p;    /* push back '\0' */
  641.             break;
  642.         default:
  643.             /* do nothing; Symbol already equals VIS_TOK_ERROR */
  644.             ;
  645.         }
  646.     CriteriaP = p;
  647.     return;
  648.     }
  649.  
  650.  
  651.  
  652. /******************************************************************************
  653.  * LookupName
  654.  *    finds the token corresponding to a character string, if any exists
  655.  *****************************************************************************/
  656.  
  657. static int
  658. LookupName(char* name) {
  659.     static NameMappingT map[] = {    /* NOTE:  Must be sorted! */
  660.         {"a",         VIS_VAR_A},
  661.         {"accuma",     VIS_VAR_ACCUM_A},
  662.         {"accumb",     VIS_VAR_ACCUM_B},
  663.         {"accumg",     VIS_VAR_ACCUM_G},
  664.         {"accumr",     VIS_VAR_ACCUM_R},
  665.         {"accumrgb",     VIS_VAR_ACCUM_RGB},
  666.         {"accumrgba",     VIS_VAR_ACCUM_RGBA},
  667.         {"aux",     VIS_VAR_AUX},
  668.         {"b",         VIS_VAR_B},
  669.         {"ci",         VIS_VAR_CI},
  670.         {"db",         VIS_VAR_DB},
  671.         {"g",         VIS_VAR_G},
  672.         {"id",         VIS_VAR_ID},
  673.         {"level",     VIS_VAR_LEVEL},
  674.         {"main",    VIS_VAR_MAIN},
  675.         {"max",     VIS_SORT_MAX},
  676.         {"min",     VIS_SORT_MIN},
  677.         {"mono",     VIS_VAR_MONO},
  678.         {"ms",         VIS_VAR_MS},
  679.         {"overlay",    VIS_VAR_OVERLAY},
  680.         {"r",         VIS_VAR_R},
  681.         {"rgb",     VIS_VAR_RGB},
  682.         {"rgba",     VIS_VAR_RGBA},
  683.         {"s",         VIS_VAR_S},
  684.         {"sb",         VIS_VAR_SB},
  685.         {"stereo",     VIS_VAR_STEREO},
  686.         {"underlay",    VIS_VAR_UNDERLAY},
  687.         {"z",         VIS_VAR_Z}
  688.         };
  689.     NameMappingT n;
  690.     NameMappingT* m;
  691.  
  692.     n.name = name;
  693.     m = bsearch(&n, map, sizeof(map)/sizeof(map[0]), sizeof(map[0]),
  694.         CompareNames);
  695.     return (m == NULL)? VIS_TOK_ERROR: m->value;
  696.     }
  697.  
  698.  
  699.  
  700. /******************************************************************************
  701.  * ParseArithExpr
  702.  *    Syntax:    arithExpr -> arithTerm {('+'|'-') arithTerm}
  703.  *****************************************************************************/
  704.  
  705. static int
  706. ParseArithExpr(void) {
  707.     int status;
  708.     int op;
  709.  
  710.     status = ParseArithTerm();
  711.     if (status != VIS_PRESENT)
  712.         return status;
  713.  
  714.     for (;;) {
  715.         if (Symbol == VIS_OP_ADD || Symbol == VIS_OP_SUB) {
  716.             op = Symbol;
  717.             GetSymbol();
  718.             if (ParseArithTerm() != VIS_PRESENT)
  719.                 return VIS_SYNTAX_ERROR;
  720.             Emit(op);
  721.             }
  722.         else
  723.             return VIS_PRESENT;
  724.         }
  725.     }
  726.  
  727.  
  728.  
  729. /******************************************************************************
  730.  * ParseArithFactor
  731.  *    Syntax:    arithFactor -> ['+'|'-'|'!'] arithPrimary
  732.  *****************************************************************************/
  733.  
  734. static int
  735. ParseArithFactor(void) {
  736.     int op;
  737.  
  738.     if (Symbol == VIS_OP_ADD || Symbol == VIS_OP_SUB
  739.       || Symbol == VIS_OP_NOT) {
  740.         op = Symbol;
  741.         GetSymbol();
  742.         if (ParseArithPrimary() != VIS_PRESENT)
  743.             return VIS_SYNTAX_ERROR;
  744.         if (op == VIS_OP_SUB)
  745.             Emit(VIS_OP_NEGATE);
  746.         else if (op == VIS_OP_NOT)
  747.             Emit(VIS_OP_NOT);
  748.         return VIS_PRESENT;
  749.         }
  750.  
  751.     return ParseArithPrimary();
  752.     }
  753.  
  754.  
  755.  
  756. /******************************************************************************
  757.  * ParseArithPrimary
  758.  *    Syntax:    arithPrimary -> variable | constant | '(' expression ')'
  759.  *****************************************************************************/
  760.  
  761. static int
  762. ParseArithPrimary(void) {
  763.     if (VIS_FIRST_VAR <= Symbol && Symbol <= VIS_LAST_VAR) {
  764.         Emit(Symbol);
  765.         GetSymbol();
  766.         return VIS_PRESENT;
  767.         }
  768.  
  769.     if (Symbol == VIS_TOK_CONSTANT) {
  770.         Emit(VIS_TOK_CONSTANT);
  771.         Emit(Value);
  772.         GetSymbol();
  773.         return VIS_PRESENT;
  774.         }
  775.  
  776.     if (Symbol == VIS_TOK_LPAREN) {
  777.         GetSymbol();
  778.         if (ParseExpression() != VIS_PRESENT)
  779.             return VIS_SYNTAX_ERROR;
  780.         if (Symbol == VIS_TOK_RPAREN) {
  781.             GetSymbol();
  782.             return VIS_PRESENT;
  783.             }
  784.         else
  785.             return VIS_SYNTAX_ERROR;
  786.         }
  787.  
  788.     return VIS_ABSENT;
  789.     }
  790.  
  791.  
  792.  
  793. /******************************************************************************
  794.  * ParseArithTerm
  795.  *    Syntax:    arithTerm -> arithFactor {('*'|'/'|'%') arithFactor}
  796.  *****************************************************************************/
  797.  
  798. static int
  799. ParseArithTerm(void) {
  800.     int status;
  801.     int op;
  802.  
  803.     status = ParseArithFactor();
  804.     if (status != VIS_PRESENT)
  805.         return status;
  806.  
  807.     for (;;) {
  808.         if (Symbol == VIS_OP_MUL
  809.          || Symbol == VIS_OP_DIV
  810.          || Symbol == VIS_OP_MOD) {
  811.             op = Symbol;
  812.             GetSymbol();
  813.             if (ParseArithFactor() != VIS_PRESENT)
  814.                 return VIS_SYNTAX_ERROR;
  815.             Emit(op);
  816.             }
  817.         else
  818.             return VIS_PRESENT;
  819.         }
  820.     }
  821.  
  822.  
  823.  
  824. /******************************************************************************
  825.  * ParseBoolFactor
  826.  *   Syntax:  boolFactor -> arithExpr [('<'|'>'|'<='|'>='|'=='|'!=') arithExpr]
  827.  *****************************************************************************/
  828.  
  829. static int
  830. ParseBoolFactor(void) {
  831.     int status;
  832.     int op;
  833.  
  834.     status = ParseArithExpr();
  835.     if (status != VIS_PRESENT)
  836.         return status;
  837.  
  838.     if (Symbol == VIS_OP_LT
  839.      || Symbol == VIS_OP_GT
  840.      || Symbol == VIS_OP_LE
  841.      || Symbol == VIS_OP_GE
  842.      || Symbol == VIS_OP_EQ
  843.      || Symbol == VIS_OP_NE) {
  844.         op = Symbol;
  845.         GetSymbol();
  846.         if (ParseArithExpr() != VIS_PRESENT)
  847.             return VIS_SYNTAX_ERROR;
  848.         Emit(op);
  849.         }
  850.  
  851.     return VIS_PRESENT;
  852.     }
  853.  
  854.  
  855.  
  856. /******************************************************************************
  857.  * ParseBoolTerm
  858.  *    Syntax:    boolTerm -> boolFactor {'&&' boolFactor}
  859.  *****************************************************************************/
  860.  
  861. static int
  862. ParseBoolTerm(void) {
  863.     int status;
  864.  
  865.     status = ParseBoolFactor();
  866.     if (status != VIS_PRESENT)
  867.         return status;
  868.  
  869.     for (;;) {
  870.         if (Symbol == VIS_OP_AND) {
  871.             GetSymbol();
  872.             if (ParseBoolFactor() != VIS_PRESENT)
  873.                 return VIS_SYNTAX_ERROR;
  874.             Emit(VIS_OP_AND);
  875.             }
  876.         else
  877.             return VIS_PRESENT;
  878.         }
  879.     }
  880.  
  881.  
  882.  
  883. /******************************************************************************
  884.  * ParseCriteria
  885.  *    Syntax:  criteria -> criterion {',' criterion}
  886.  *****************************************************************************/
  887.  
  888. static int
  889. ParseCriteria(void) {
  890.     int status;
  891.  
  892.     /* Consider only GLX-capable Visuals: */
  893.     Emit(VIS_VAR_GLX);
  894.  
  895.     /* Process all the user-specified conditions and sort keys: */
  896.     status = ParseCriterion();
  897.     if (status != VIS_PRESENT)
  898.         return status;
  899.  
  900.     for (;;) {
  901.         if (Symbol == VIS_TOK_SEPARATOR) {
  902.             GetSymbol();
  903.             if (ParseCriterion() != VIS_PRESENT)
  904.                 return VIS_SYNTAX_ERROR;
  905.             }
  906.         else if (Symbol == VIS_OP_END)
  907.             return VIS_PRESENT;
  908.         else
  909.             return VIS_SYNTAX_ERROR;
  910.         }
  911.     }
  912.  
  913.  
  914.  
  915. /******************************************************************************
  916.  * ParseCriterion
  917.  *    Syntax:  criterion -> sortKey | expression
  918.  *****************************************************************************/
  919.  
  920. static int
  921. ParseCriterion(void) {
  922.     int status;
  923.  
  924.     status = ParseSortKey();
  925.     if (status == VIS_ABSENT)
  926.         status = ParseExpression();
  927.  
  928.     if (status == VIS_PRESENT)
  929.         Emit(VIS_OP_AND);
  930.     return status;
  931.     }
  932.  
  933.  
  934.  
  935. /******************************************************************************
  936.  * ParseExpression
  937.  *    Syntax:  expression -> boolTerm {'||' boolTerm}
  938.  *****************************************************************************/
  939.  
  940. static int
  941. ParseExpression(void) {
  942.     int status;
  943.  
  944.     status = ParseBoolTerm();
  945.     if (status != VIS_PRESENT)
  946.         return status;
  947.  
  948.     for (;;) {
  949.         if (Symbol == VIS_OP_OR) {
  950.             GetSymbol();
  951.             if (ParseBoolTerm() != VIS_PRESENT)
  952.                 return VIS_SYNTAX_ERROR;
  953.             Emit(VIS_OP_OR);
  954.             }
  955.         else
  956.             return VIS_PRESENT;
  957.         }
  958.     }
  959.  
  960.  
  961.  
  962. /******************************************************************************
  963.  * ParseSortKey
  964.  *    Syntax:  sortKey -> ('max'|'min') variable
  965.  *****************************************************************************/
  966.  
  967. static int
  968. ParseSortKey(void) {
  969.     if (Symbol == VIS_SORT_MAX || Symbol == VIS_SORT_MIN) {
  970.         EmitKey(Symbol);
  971.         GetSymbol();
  972.         if (VIS_FIRST_VAR <= Symbol && Symbol <= VIS_LAST_VAR) {
  973.             EmitKey(Symbol);
  974.             /*
  975.              * When sorting, eliminate visuals with a zero value
  976.              * for the key.  This is hard to justify on grounds
  977.              * of orthogonality, but it seems to yield the right
  978.              * behavior.
  979.              */
  980.             Emit(Symbol);
  981.             GetSymbol();
  982.             return VIS_PRESENT;
  983.             }
  984.         else
  985.             return VIS_SYNTAX_ERROR;
  986.         }
  987.  
  988.     return VIS_ABSENT;
  989.     }
  990.  
  991.  
  992.  
  993. /******************************************************************************
  994.  * visGetGLXVisualInfo
  995.  *    Return an array of XVisualInfo structures satisfying the current
  996.  *    visual selection expression, sorted according to the current sort
  997.  *    keys, for the specified X11 display and screen.
  998.  *
  999.  * Returns NULL if malloc() fails, otherwise a list of XVisualInfo structures.
  1000.  * The memory referenced by the returned pointer should be freed with free()
  1001.  *    when it's no longer needed.
  1002.  *****************************************************************************/
  1003.  
  1004. XVisualInfo*
  1005. visGetGLXVisualInfo(Display* dpy, int screen, int* nVInfo) {
  1006.     XVisualInfo template;
  1007.     XVisualInfo* v;
  1008.     XVisualInfo* newV;
  1009.     XVisualInfo** vp;
  1010.     int i;
  1011.     int n;
  1012.  
  1013.     *nVInfo = 0;        /* insurance against careless apps */
  1014.     DisplayPointer = dpy;    /* needed by FetchVariable routine */
  1015.  
  1016.     /* Get the list of raw XVisualInfo structures: */
  1017.     template.screen = screen;
  1018.     if (!(v = XGetVisualInfo(dpy,VisualScreenMask,&template,&n)))
  1019.         return NULL;
  1020.  
  1021.     /* Construct a list of pointers to the XVisualInfo structures: */
  1022.     vp = (XVisualInfo**) malloc(n * sizeof(XVisualInfo*));
  1023.     if (!vp) {
  1024.         XFree(v);
  1025.         return NULL;
  1026.         }
  1027.     for (i = 0; i < n; ++i)
  1028.         vp[i] = v + i;
  1029.  
  1030.     /* Delete pointers to visuals that don't meet the criteria: */
  1031.     FilterVisuals(vp, &n);
  1032.  
  1033.     /* Sort the visuals according to the sort keys: */
  1034.     qsort(vp, n, sizeof(XVisualInfo*), CompareVisuals);
  1035.  
  1036.     /* Pack the XVisualInfo structures into the output array: */
  1037.     newV = (XVisualInfo*) malloc(n * sizeof(XVisualInfo));
  1038.     if (!newV) {
  1039.         XFree(v);
  1040.         free(vp);
  1041.         return NULL;
  1042.         }
  1043.     for (i = 0; i < n; ++i)
  1044.         newV[i] = *vp[i];
  1045.  
  1046.     /* Clean up and return the new array of XVisualInfo structures: */
  1047.     XFree(v);
  1048.     free(vp);
  1049.     *nVInfo = n;
  1050.     return newV;
  1051.     }
  1052.  
  1053.  
  1054.  
  1055. /******************************************************************************
  1056.  * visPixelFormat
  1057.  *    Specifies sort keys and visual selection expression for use by a
  1058.  *    subsequent call to visGetXVisualInfo.
  1059.  *
  1060.  * Returns nonzero for success, zero for failure (syntax error in expression).
  1061.  *****************************************************************************/
  1062.  
  1063. int
  1064. visPixelFormat(const char* criteria) {
  1065.     int status;
  1066.  
  1067.     CriteriaP = (char*) criteria;
  1068.     ConditionP = Condition;
  1069.     SortKeyP = SortKeys;
  1070.     GetSymbol();
  1071.     status = ParseCriteria();
  1072.     if (status != VIS_PRESENT) {
  1073.         /*
  1074.          * An error occurred. Make things sane, in case
  1075.          * visGetXVisualInfo is called without checking.
  1076.          */
  1077.         ConditionP = Condition;
  1078.         Emit(VIS_TOK_CONSTANT);
  1079.         Emit(0);
  1080.         SortKeyP = SortKeys;
  1081.         }
  1082.     Emit(VIS_OP_END);
  1083.  
  1084.     /* Make the final sort in order of increasing visual ID: */
  1085.     EmitKey(VIS_SORT_MIN);
  1086.     EmitKey(VIS_VAR_ID);
  1087.     EmitKey(VIS_OP_END);
  1088.  
  1089.     return status == VIS_PRESENT;
  1090.     }
  1091.  
  1092.  
  1093.  
  1094. #if DEBUG
  1095. /******************************************************************************
  1096.  * SymbolToString
  1097.  *    Debugging routine to convert a symbol to a printable representation
  1098.  *****************************************************************************/
  1099.  
  1100. static char*
  1101. SymbolToString(int symbol) {
  1102.     static NameMappingT t[] = {
  1103.         {"VIS_ABSENT",        VIS_ABSENT},
  1104.         {"VIS_OP_ADD",        VIS_OP_ADD},
  1105.         {"VIS_OP_AND",        VIS_OP_AND},
  1106.         {"VIS_OP_DIV",        VIS_OP_DIV},
  1107.         {"VIS_OP_END",        VIS_OP_END},
  1108.         {"VIS_OP_EQ",        VIS_OP_EQ},
  1109.         {"VIS_OP_GE",        VIS_OP_GE},
  1110.         {"VIS_OP_GT",        VIS_OP_GT},
  1111.         {"VIS_OP_LE",        VIS_OP_LE},
  1112.         {"VIS_OP_LT",        VIS_OP_LT},
  1113.         {"VIS_OP_MOD",        VIS_OP_MOD},
  1114.         {"VIS_OP_MUL",        VIS_OP_MUL},
  1115.         {"VIS_OP_NE",        VIS_OP_NE},
  1116.         {"VIS_OP_NEGATE",    VIS_OP_NEGATE},
  1117.         {"VIS_OP_NOT",        VIS_OP_NOT},
  1118.         {"VIS_OP_OR",        VIS_OP_OR},
  1119.         {"VIS_OP_SUB",        VIS_OP_SUB},
  1120.         {"VIS_PRESENT",        VIS_PRESENT},
  1121.         {"VIS_SORT_MAX",    VIS_SORT_MAX},
  1122.         {"VIS_SORT_MIN",    VIS_SORT_MIN},
  1123.         {"VIS_SYNTAX_ERROR",    VIS_SYNTAX_ERROR},
  1124.         {"VIS_TOK_CONSTANT",    VIS_TOK_CONSTANT},
  1125.         {"VIS_TOK_ERROR",    VIS_TOK_ERROR},
  1126.         {"VIS_TOK_LPAREN",    VIS_TOK_LPAREN},
  1127.         {"VIS_TOK_RPAREN",    VIS_TOK_RPAREN},
  1128.         {"VIS_TOK_SEPARATOR",    VIS_TOK_SEPARATOR},
  1129.         {"VIS_VAR_A",        VIS_VAR_A},
  1130.         {"VIS_VAR_ACCUM_A",    VIS_VAR_ACCUM_A},
  1131.         {"VIS_VAR_ACCUM_B",    VIS_VAR_ACCUM_B},
  1132.         {"VIS_VAR_ACCUM_G",    VIS_VAR_ACCUM_G},
  1133.         {"VIS_VAR_ACCUM_R",    VIS_VAR_ACCUM_R},
  1134.         {"VIS_VAR_ACCUM_RGB",    VIS_VAR_ACCUM_RGB},
  1135.         {"VIS_VAR_ACCUM_RGBA",    VIS_VAR_ACCUM_RGBA},
  1136.         {"VIS_VAR_AUX",        VIS_VAR_AUX},
  1137.         {"VIS_VAR_B",        VIS_VAR_B},
  1138.         {"VIS_VAR_CI",        VIS_VAR_CI},
  1139.         {"VIS_VAR_DB",        VIS_VAR_DB},
  1140.         {"VIS_VAR_G",        VIS_VAR_G},
  1141.         {"VIS_VAR_GLX",        VIS_VAR_GLX},
  1142.         {"VIS_VAR_ID",        VIS_VAR_ID},
  1143.         {"VIS_VAR_LEVEL",    VIS_VAR_LEVEL},
  1144.         {"VIS_VAR_MAIN",    VIS_VAR_MAIN},
  1145.         {"VIS_VAR_MONO",    VIS_VAR_MONO},
  1146.         {"VIS_VAR_MS",        VIS_VAR_MS},
  1147.         {"VIS_VAR_OVERLAY",    VIS_VAR_OVERLAY},
  1148.         {"VIS_VAR_R",        VIS_VAR_R},
  1149.         {"VIS_VAR_RGB",        VIS_VAR_RGB},
  1150.         {"VIS_VAR_RGBA",    VIS_VAR_RGBA},
  1151.         {"VIS_VAR_S",        VIS_VAR_S},
  1152.         {"VIS_VAR_SB",        VIS_VAR_SB},
  1153.         {"VIS_VAR_STEREO",    VIS_VAR_STEREO},
  1154.         {"VIS_VAR_UNDERLAY",    VIS_VAR_UNDERLAY},
  1155.         {"VIS_VAR_Z",        VIS_VAR_Z},
  1156.         };
  1157.     int i;
  1158.  
  1159.     for (i = 0; i < sizeof(t) / sizeof(t[0]); ++i)
  1160.         if (t[i].value == symbol)
  1161.             return t[i].name;
  1162.  
  1163.     return "UNKNOWN";
  1164.     }
  1165. #endif
  1166.